import json
from datetime import datetime
# 导入聊天管理器和 json
from fastapi import WebSocket, status, WebSocketDisconnect, UploadFile, File, Form, APIRouter, HTTPException, Depends
from fastapi.responses import FileResponse, StreamingResponse

from ..config import GLOBAL_FILES_DIR
from ..dependencies import verify_token, get_current_user, get_current_teacher, get_client_ip
# 导入聊天管理器
from ..services.chat_handler import manager, save_chat_message

from typing import Optional
from pathlib import Path

from ..database import get_db_connection
from ..services.file_handler import delete_file_safely
from ..services.file_service import save_file_globally, get_file_lock, stream_file


async def broadcast_file_update(course_id: int, message_text: str):
    """
    查找与某个课程ID关联的所有班级课堂 (聊天室)，并广播一条系统消息。
    """
    room_ids = []
    try:
        with get_db_connection() as conn:
            # 查找所有使用此 course_id 的 class_offering (即聊天室)
            rooms = conn.execute(
                "SELECT id FROM class_offerings WHERE course_id = ?",
                (course_id,)
            ).fetchall()
            room_ids = [room['id'] for room in rooms]

    except Exception as e:
        print(f"[ERROR] 广播文件更新时，查找聊天室失败: {e}")
        return

    if room_ids:
        # 格式化系统消息
        message_obj = {
            "type": "system",
            "message": message_text
        }
        message_json = json.dumps(message_obj)

        # 广播到所有相关的聊天室
        for room_id in room_ids:
            try:
                await manager.broadcast(room_id, message_json)
            except Exception as e:
                print(f"[ERROR] 广播到聊天室 {room_id} 失败: {e}")


router = APIRouter()


@router.post("/api/courses/{course_id}/files/upload")
async def upload_course_file(
        course_id: int,
        file: UploadFile = File(...),
        is_public: bool = Form(True),
        is_teacher_resource: bool = Form(False),
        user: dict = Depends(get_current_teacher)
):
    """上传课程资源文件(教师)"""
    # 检查课程权限
    with get_db_connection() as conn:
        course = conn.execute(
            "SELECT id FROM courses WHERE id = ? AND created_by_teacher_id = ?",
            (course_id, user['id'])
        ).fetchone()
        if not course:
            raise HTTPException(403, "无权操作此课程")

        # 全局保存文件
        file_info = await save_file_globally(file)
        if not file_info:
            raise HTTPException(500, "文件保存失败")

        try:
            conn.execute("""
                         INSERT INTO course_files
                         (course_id, file_name, file_hash, file_size, is_public, is_teacher_resource)
                         VALUES (?, ?, ?, ?, ?, ?)
                         """, (
                             course_id,
                             file.filename,
                             file_info["hash"],
                             file_info["size"],
                             is_public,
                             is_teacher_resource
                         ))
            conn.commit()

        except Exception as e:
            raise HTTPException(500, f"数据库操作失败: {e}")

        # --- 新增：广播消息 ---
        try:
            # 1. 构造消息
            system_message = json.dumps({
                "type": "system",
                "message": f"老师上传了新文件: {file.filename}。请刷新列表查看。",
                "highlight": True  # 增加高亮标记
            })

            # 2. 找到所有使用此 course_id 的课堂
            offerings = conn.execute(
                "SELECT id FROM class_offerings WHERE course_id = ?",
                (course_id,)
            ).fetchall()

            # 3. 向所有相关课堂广播
            for offering in offerings:
                await manager.broadcast(offering['id'], system_message)
        except Exception as e:
            print(f"[ERROR] 广播上传消息失败: {e}")
        # --- 广播结束 ---

    return {
        "status": "success",
        "message": f"文件 '{file.filename}' 上传成功"
    }


@router.delete("/api/courses/{course_id}/files/{file_id}")
async def delete_course_file(
        course_id: int,
        file_id: int,
        user: dict = Depends(get_current_teacher)
):
    """删除课程文件"""
    with get_db_connection() as conn:
        # 检查权限
        course = conn.execute(
            "SELECT id FROM courses WHERE id = ? AND created_by_teacher_id = ?",
            (course_id, user['id'])
        ).fetchone()
        if not course:
            raise HTTPException(403, "无权操作此课程")

        # 获取文件信息
        file_data = conn.execute(
            "SELECT file_name, file_hash FROM course_files WHERE id = ? AND course_id = ?",
            (file_id, course_id)
        ).fetchone()
        if not file_data:
            raise HTTPException(404, "文件不存在")

        # 删除物理文件
        save_status = await delete_file_safely(Path(GLOBAL_FILES_DIR) / file_data['file_hash'])

        # 删除数据库记录
        conn.execute("DELETE FROM course_files WHERE id = ?", (file_id,))
        conn.commit()

        # --- 新增：广播消息 ---
        try:
            # 1. 构造消息
            system_message = json.dumps({
                "type": "system",
                "message": f"老师删除了文件: {file_data['file_name']}",
                "highlight": True
            })

            # 2. 找到所有使用此 course_id 的课堂
            offerings = conn.execute(
                "SELECT id FROM class_offerings WHERE course_id = ?",
                (course_id,)
            ).fetchall()

            # 3. 向所有相关课堂广播
            for offering in offerings:
                await manager.broadcast(offering['id'], system_message)
        except Exception as e:
            print(f"[ERROR] 广播删除消息失败: {e}")
        # --- 广播结束 ---

    return {"status": "success",
            "message": "文件删除成功，" + ("物理文件已删除。" if save_status else "但物理文件删除失败。")}


@router.get("/download/course_file/{file_id}")
async def download_course_file(
        file_id: int,
        user: Optional[dict] = Depends(get_current_user)
):
    """下载课程文件(支持断点续传和并发控制)"""
    if not user:
        raise HTTPException(401, "Not authenticated")

    with get_db_connection() as conn:
        file_info = conn.execute("""
                                 SELECT cf.*, c.created_by_teacher_id
                                 FROM course_files cf
                                          JOIN courses c ON cf.course_id = c.id
                                 WHERE cf.id = ?
                                 """, (file_id,)).fetchone()

    if not file_info:
        raise HTTPException(404, "文件不存在")

    # 权限检查
    if file_info['is_teacher_resource'] and user['role'] != 'teacher':
        raise HTTPException(403, "无权访问教师资源")

    file_path = Path(GLOBAL_FILES_DIR) / file_info['file_hash']
    if not file_path.exists():
        raise HTTPException(404, "文件不存在")

    # 获取文件锁
    file_lock = await get_file_lock(file_info['file_hash'])

    async def streamed_file():
        async with file_lock:  # 使用异步锁控制并发
            async for chunk in stream_file(file_path):
                yield chunk

    return StreamingResponse(
        streamed_file(),
        media_type='application/octet-stream',
        headers={
            'Content-Disposition': f'attachment; filename="{file_info["file_name"]}"',
            'Content-Length': str(file_info['file_size'])
        }
    )


# --- 【新增】用于异步刷新文件列表的 API ---
@router.get("/api/courses/{class_offering_id}/files")
async def get_classroom_files(
        class_offering_id: int,
        user: dict = Depends(get_current_user)
):
    """获取指定课堂(课程)的文件列表"""
    with get_db_connection() as conn:
        # 1. 根据课堂ID找到课程ID
        offering = conn.execute(
            "SELECT course_id FROM class_offerings WHERE id = ?",
            (class_offering_id,)
        ).fetchone()

        if not offering:
            raise HTTPException(404, "Classroom not found")
        course_id = offering['course_id']

        # 2. 根据用户角色获取文件列表
        query = "SELECT id, file_name, file_size FROM course_files WHERE course_id = ?"
        params = [course_id]

        # 学生看不到教师资源
        if user['role'] != 'teacher':
            query += " AND is_teacher_resource = 0"

        files = conn.execute(query, params).fetchall()

        # 3. 告知前端当前是否是教师 (用于显示删除按钮)
        is_teacher = (user['role'] == 'teacher')

    # 将 sqlite3.Row 转换为字典列表
    return {"files": [dict(f) for f in files], "is_teacher": is_teacher}


# (原有的 download_course_file V4.0 - 已被上面的 /download/course_file/{file_id} 替换)
# (原有的 download_submission_file V4.0)

@router.get("/submissions/download/{file_id}", response_class=FileResponse)
async def download_submission_file(file_id: int, user: Optional[dict] = Depends(get_current_user)):
    """V4.0: 下载学生提交的文件"""
    if not user: raise HTTPException(401, "Not authenticated")

    with get_db_connection() as conn:
        file_info = conn.execute(
            """SELECT sf.*, s.student_pk_id
               FROM submission_files sf
                        JOIN submissions s ON sf.submission_id = s.id
               WHERE sf.id = ?""", (file_id,)
        ).fetchone()

    if not file_info: raise HTTPException(404, "File not found")

    # 安全检查：只允许教师 或 文件所有者学生 下载
    if user['role'] != 'teacher' and file_info['student_pk_id'] != user['id']:
        raise HTTPException(403, "Permission denied")

    file_path = Path(file_info['stored_path'])
    if not file_path.exists(): raise HTTPException(404, "File not found on disk")

    return FileResponse(file_path, filename=file_info['original_filename'])


@router.websocket("/ws/{class_offering_id}")
async def websocket_endpoint(websocket: WebSocket, class_offering_id: int):
    """V4.0: 支持多房间的 WebSocket"""
    # 获取客户端IP
    client_ip = None
    try:
        # 首先尝试从 headers 获取真实IP（反向代理情况）
        forwarded_for = websocket.headers.get("x-forwarded-for")
        if forwarded_for:
            client_ip = forwarded_for.split(',')[0].strip()
        else:
            # 使用连接IP
            client_ip = websocket.client.host
    except Exception as e:
        print(f"[WS ERROR] 获取客户端IP失败: {e}")
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return

    token = websocket.cookies.get("access_token")

    # 使用新的verify_token函数，传入client_ip
    user = verify_token(token, client_ip)
    if user is None:
        print(f"[WS ERROR] Token验证失败 - IP: {client_ip}")
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return

    # TODO: 验证用户是否有权进入这个 class_offering_id 房间

    client_id = f"{user['role']}_{user['id']}"
    user['id'] = client_id  # 使用唯一的 client_id

    await manager.connect(websocket, user)
    try:
        while True:
            data = await websocket.receive_text()
            message_obj = {
                "type": "chat",
                "sender": user['name'],
                "role": user['role'],
                "message": data,
                "timestamp": datetime.now().strftime("%H:%M")
            }
            # 保存消息
            db_message = {
                "class_offering_id": class_offering_id,
                "user_id": user['id'],
                "user_name": user['name'],
                "user_role": user['role'],
                "message": data,
                "timestamp": datetime.now().isoformat()
            }
            await save_chat_message(class_offering_id, db_message)
            # 广播消息
            await manager.broadcast(class_offering_id, json.dumps(message_obj))
    except WebSocketDisconnect:
        await manager.disconnect(websocket, client_id)
    except Exception as e:
        print(f"[WS ERROR] {e}")
        await manager.disconnect(websocket, client_id)